package com.weijia.zh.qa.config;

import com.weijia.zh.common.utils.JsonPare;
import com.weijia.zh.qa.dao.ProblemDao;
import com.weijia.zh.qa.entity.ProblemEntity;
import com.weijia.zh.qa.entity.ReplyEntity;
import com.weijia.zh.qa.key.Key;
import com.weijia.zh.qa.service.ProblemService;
import com.weijia.zh.qa.service.ReplyService;
import com.weijia.zh.qa.utils.RedisUtil;
import com.weijia.zh.qa.vo.HotProblem;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
@EnableScheduling
@EnableAsync
@Slf4j
public class FixedTime {


    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private ProblemService problemService;

    @Autowired
    private ProblemDao problemDao;

    @Autowired
    private ReplyService replyService;

    @Autowired
    private Key key;

    @Autowired
    private RedissonClient redissonClient;

    @Async
    @Scheduled(cron = "0 * * * * ? *")//每分钟执行一次
    public void updateHot(){

        RLock lock = this.redissonClient.getLock(this.key.getFixed());
        boolean tryLock = lock.tryLock();
        if(!tryLock)//没有获取到锁就不做了，因为这说明有其他服务器做了
            return;

        try {
            log.info("进入时任务生成热榜数据和热点数据缓存===========");
            Set<ZSetOperations.TypedTuple<Object>> problemWithSores = this.redisUtil.zReverseRangeWithScores(this.key.getVisits(), 0, -1);

            log.info("查询得到problemWithSores：{}",problemWithSores);

            this.redisUtil.del(this.key.getVisits());//删除
            log.info("删除redis的浏览量记录键");

//        将浏览量更新数据库
            boolean b = this.problemService.updateProblemVisit(problemWithSores);
            log.info("更新数据库:{}",b);

//        写入缓存,更新热点数据
            this.updateHot(problemWithSores);
            log.info("写入缓存完成");
        } finally {
            lock.unlock();
        }
    }

    private void updateHot(Set<ZSetOperations.TypedTuple<Object>> problemWithSores){

        //查询前5位的问题的具体信息及其问题并写入缓存

        if (problemWithSores.size() > 0)//只要有热榜，就把旧热榜删除
            this.redisUtil.del(this.key.getHot());
        log.info("开始写入缓存,更新热点数据");
        //取出前5位热榜问题
        int i = 0;
        Iterator<ZSetOperations.TypedTuple<Object>> iterator = problemWithSores.iterator();
        while(iterator.hasNext() && i <5){
            ZSetOperations.TypedTuple<Object> problemWithSore = iterator.next();
            log.info("problemWithSore：{}",problemWithSore);
            Long id = JsonPare.pare(problemWithSore.getValue(), Long.class);
            log.info("id：{}",id);
            //查询问题信息及其回答信息
            ProblemEntity problem = this.problemDao.selectById(id);
            if (problem == null) //如果查询不到问题，直接下一个
                continue;
            List<ReplyEntity> replyEntities = this.replyService.searchReplyById(id);
            log.info("problem：{}",problem);
            log.info("replyEntities：{}",replyEntities);
            //生成热搜榜展示数据
            HotProblem showHotProblem = new HotProblem();
            showHotProblem.setId(problem.getId());
            showHotProblem.setTitle(problem.getTitle());
            showHotProblem.setVisits(JsonPare.pare(problemWithSore.getScore(),Long.class));
            log.info("showHotProblem：{}",showHotProblem);
            // 加入redis
//            如果索引修改不成功，则从右边加入list。不这样做可能由于没有该索引而报错
            this.redisUtil.lSet(this.key.getHot(),showHotProblem);
            this.redisUtil.set(this.key.getProblem() + ":" + id,problem,60*60*1);
            this.redisUtil.del(this.key.getReplies()+":"+id);//先将原缓存清空
//            没有回答就不存
            this.redisUtil.lSetOrNull(this.key.getReplies()+":"+id,replyEntities,60*60*1);
            i++;
        }

    }

}
